<?php

/* 
 * Project: colobok
 * and open the template in the editor.
 * @author: Sviatoslav Mysachenko <svyatoslavik@gmail.com>
 */

namespace map;

class Tile{
    protected $__x;
    protected $__y;
    protected $__zoom;
    public function  __construct($x, $y, $zoom) {

        $this->__x = $x;
        $this->__y = $y;
        $this->__zoom = $zoom;
    }
    public static function getTileByQuadTree($quadTreeStr){
        $zoom = strlen($quadTreeStr)-1;
        $x = 0;
        $y = 0;
        for($i=$zoom-1, $idx = 1; $i>=0; $i--, $idx++){
            $sig = (int) $quadTreeStr[$idx];
            $addNum =pow(2, $i);
            $x += ($sig==1||$sig==3)?$addNum:0;
            $y += ($sig==1||$sig==0)?$addNum:0;
        }
        return new self($x, $y, $zoom);
    }

    /**
     * http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#PHP
     * @param <type> $lat
     * @param <type> $lng
     * @param <type> $zoom
     */
    public static function getTileByLanLngZoom($lat, $lng, $zoom){
        $xyzoom = self::getXYZByLatLng($lat, $lng, $zoom);
        return new self($xyzoom['x'], $xyzoom['y'], $xyzoom['zoom']);
    }
    private static function getXYZByLatLng($lat, $lng, $zoom){
        $xtile = floor((($lng + 180) / 360) * pow(2, $zoom));
        $ytile = floor((1 - log(tan(deg2rad($lat)) + 1 / cos(deg2rad($lat))) / pi()) /2 * pow(2, $zoom));
        return array('x'=>$xtile, 'y' => $ytile, 'zoom'=>$zoom);
    }
    public function clearCache($scope){
        
    }
    public function zoom(){return $this->__zoom;}
    public function x(){return $this->__x;}
    public function y(){return $this->__y;}
    /**
     * get Quad Tree format quad tree:
     * ___________
     * {| 2 | 3 |}
     * {| 0 | 1 |}
     * ___________
     * @return string
     */
    public function getQuadTree(){
        $transform = array('2','3','0','1');
        $quad = "";
        for ($i = $this->zoom(); $i > 0; $i--){
            $mask = 1 << ($i - 1); // analog pow(2, $i-1);
            $cell = 0;
            if (($this->x() & $mask) != 0)
                $cell++;
            if (($this->y() & $mask) != 0)
                $cell += 2;
            $quad .= $transform[$cell];
        }
        return $quad;
    }

    public function getBounds(){
        return $this->__getBoundsFromXYZ(
                    $this->__x,
                    $this->__y,
                    $this->__zoom
                );
    }

    protected  function __getBoundsFromXYZ($x, $y, $zoom) {
      $debug = false;
      $lon      = -180;
      $lonWidth = 360;
      $lat       = -1;
      $latHeight = 2;

      $tilesAtThisZoom = 1 << ($zoom);
      $lonWidth  = 360.0 / $tilesAtThisZoom;
      $lon       = -180 + ($x * $lonWidth);
      $latHeight = 2.0 / $tilesAtThisZoom;
      $lat       = (($tilesAtThisZoom/2 - $y-1) * $latHeight);

      if ($debug) {echo("(uniform) lat:$lat latHt:$latHeight<br>");}
      // convert lat and latHeight to degrees in a transverse mercator projection
      // note that in fact the coordinates go from about -85 to +85 not -90 to 90!
      $latHeight += $lat;
      $latHeight = (2 * atan(exp(PI() * $latHeight))) - (PI() / 2);
      $latHeight *= (180 / PI());

      $lat = (2 * atan(exp(PI() * $lat))) - (PI() / 2);
      $lat *= (180 / PI());


        if ($debug) {echo("pre subtract lat: $lat latHeight $latHeight<br>");}
      $latHeight -= $lat;
        if ($debug) {echo("lat: $lat latHeight $latHeight<br>");}

      if ($lonWidth < 0) {
         $lon      = $lon + $lonWidth;
         $lonWidth = -$lonWidth;
      }

      if ($latHeight < 0) {
         $lat       = $lat + $latHeight;
         $latHeight = -$latHeight;
      }
      

      return new Bounds(array(
          'swLat' => $lat,
          'swLng' => $lon,
          'neLat' => $lat + $latHeight, // $latHeight - height of tile
          'neLng' => $lon + $lonWidth  //  $lonWidth - width of tile
      ));
   }
}
